#!/usr/bin/env python3
"""
配置系统使用情况审计脚本
分析RedFire后端项目中三套配置系统的使用情况
"""

import os
import re
import json
import ast
from pathlib import Path
from typing import Dict, List, Set, Any
from dataclasses import dataclass, asdict
from datetime import datetime


@dataclass
class ConfigUsage:
    """配置使用情况数据结构"""
    file_path: str
    line_number: int
    config_system: str
    usage_type: str  # import, instantiation, method_call
    code_snippet: str
    function_context: str = ""


@dataclass
class ServiceConfigAnalysis:
    """服务配置分析结果"""
    service_name: str
    config_files: List[str]
    config_usages: List[ConfigUsage]
    config_systems_used: Set[str]
    env_variables: Set[str]
    config_dependencies: Dict[str, int]


class ConfigAuditor:
    """配置系统审计器"""
    
    def __init__(self, backend_path: str):
        self.backend_path = Path(backend_path)
        self.services_path = self.backend_path / "apps"
        self.shared_path = self.backend_path / "shared"
        
        # 三套配置系统的特征模式
        self.config_patterns = {
            "microservice_configs": [
                r"from.*microservice_configs.*import",
                r"import.*microservice_configs",
                r"microservice_configs\.",
                r"MicroserviceConfig",
                r"get_microservice_config"
            ],
            "unified_env_standards": [
                r"from.*unified_env_standards.*import",
                r"import.*unified_env_standards",
                r"unified_env_standards\.",
                r"UnifiedEnvStandards",
                r"get_env_standard"
            ],
            "unified_config_v2": [
                r"from.*unified_config_v2.*import",
                r"import.*unified_config_v2",
                r"unified_config_v2\.",
                r"UnifiedConfigV2",
                r"ConfigManager",
                r"get_config"
            ]
        }
        
        # 环境变量模式
        self.env_patterns = [
            r"os\.getenv\(['\"]([^'\"]+)['\"]",
            r"os\.environ\[['\"]([^'\"]+)['\"]\]",
            r"getenv\(['\"]([^'\"]+)['\"]",
            r"environ\[['\"]([^'\"]+)['\"]\]"
        ]
    
    def scan_file_for_config_usage(self, file_path: Path) -> List[ConfigUsage]:
        """扫描单个文件的配置使用情况"""
        usages = []
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()
        except (UnicodeDecodeError, PermissionError):
            return usages
        
        for line_num, line in enumerate(lines, 1):
            line_content = line.strip()
            
            # 检查每套配置系统的使用
            for config_system, patterns in self.config_patterns.items():
                for pattern in patterns:
                    if re.search(pattern, line_content):
                        usage_type = self._determine_usage_type(line_content, pattern)
                        function_context = self._get_function_context(lines, line_num)
                        
                        usage = ConfigUsage(
                            file_path=str(file_path.relative_to(self.backend_path)),
                            line_number=line_num,
                            config_system=config_system,
                            usage_type=usage_type,
                            code_snippet=line_content,
                            function_context=function_context
                        )
                        usages.append(usage)
        
        return usages
    
    def _determine_usage_type(self, line: str, pattern: str) -> str:
        """确定配置使用类型"""
        if "import" in line:
            return "import"
        elif re.search(r"\w+\(", line):
            return "method_call"
        elif "=" in line:
            return "instantiation"
        else:
            return "reference"
    
    def _get_function_context(self, lines: List[str], current_line: int) -> str:
        """获取当前行所在的函数上下文"""
        for i in range(current_line - 1, -1, -1):
            line = lines[i].strip()
            if line.startswith("def ") or line.startswith("class "):
                return line
        return ""
    
    def scan_for_env_variables(self, file_path: Path) -> Set[str]:
        """扫描文件中的环境变量使用"""
        env_vars = set()
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
        except (UnicodeDecodeError, PermissionError):
            return env_vars
        
        for pattern in self.env_patterns:
            matches = re.findall(pattern, content)
            env_vars.update(matches)
        
        return env_vars
    
    def find_config_files(self, service_path: Path) -> List[str]:
        """查找服务中的配置文件"""
        config_files = []
        config_file_patterns = [
            "config.py", "settings.py", "configuration.py",
            "*.config.py", "*_config.py", "env.py"
        ]
        
        for pattern in config_file_patterns:
            config_files.extend([
                str(f.relative_to(self.backend_path)) 
                for f in service_path.rglob(pattern)
                if f.is_file() and f.name.endswith('.py')
            ])
        
        return config_files
    
    def analyze_service(self, service_name: str) -> ServiceConfigAnalysis:
        """分析单个服务的配置使用情况"""
        service_path = self.services_path / service_name
        
        if not service_path.exists():
            return ServiceConfigAnalysis(
                service_name=service_name,
                config_files=[],
                config_usages=[],
                config_systems_used=set(),
                env_variables=set(),
                config_dependencies={}
            )
        
        # 查找配置文件
        config_files = self.find_config_files(service_path)
        
        # 扫描所有Python文件
        all_usages = []
        all_env_vars = set()
        
        for py_file in service_path.rglob("*.py"):
            if py_file.is_file():
                usages = self.scan_file_for_config_usage(py_file)
                all_usages.extend(usages)
                
                env_vars = self.scan_for_env_variables(py_file)
                all_env_vars.update(env_vars)
        
        # 统计配置系统使用情况
        config_systems_used = set(usage.config_system for usage in all_usages)
        
        # 统计配置依赖
        config_dependencies = {}
        for system in config_systems_used:
            config_dependencies[system] = len([
                usage for usage in all_usages 
                if usage.config_system == system
            ])
        
        return ServiceConfigAnalysis(
            service_name=service_name,
            config_files=config_files,
            config_usages=all_usages,
            config_systems_used=config_systems_used,
            env_variables=all_env_vars,
            config_dependencies=config_dependencies
        )
    
    def analyze_all_services(self) -> Dict[str, ServiceConfigAnalysis]:
        """分析所有服务的配置使用情况"""
        analyses = {}
        
        if not self.services_path.exists():
            print(f"服务目录不存在: {self.services_path}")
            return analyses
        
        for service_dir in self.services_path.iterdir():
            if (service_dir.is_dir() and 
                not service_dir.name.startswith('.') and 
                service_dir.name != '__pycache__'):
                print(f"正在分析服务: {service_dir.name}")
                analysis = self.analyze_service(service_dir.name)
                analyses[service_dir.name] = analysis
        
        return analyses
    
    def generate_summary_report(self, analyses: Dict[str, ServiceConfigAnalysis]) -> Dict[str, Any]:
        """生成配置系统使用总结报告"""
        total_services = len(analyses)
        total_config_files = sum(len(analysis.config_files) for analysis in analyses.values())
        total_usages = sum(len(analysis.config_usages) for analysis in analyses.values())
        
        # 统计每套配置系统的使用服务数
        system_usage_count = {
            "microservice_configs": 0,
            "unified_env_standards": 0,
            "unified_config_v2": 0
        }
        
        # 统计配置系统组合使用情况
        system_combinations = {}
        
        # 收集所有环境变量
        all_env_vars = set()
        
        for service_name, analysis in analyses.items():
            # 统计系统使用
            for system in analysis.config_systems_used:
                if system in system_usage_count:
                    system_usage_count[system] += 1
            
            # 统计组合使用
            systems_combo = tuple(sorted(analysis.config_systems_used))
            if systems_combo:
                system_combinations[systems_combo] = system_combinations.get(systems_combo, 0) + 1
            
            # 收集环境变量
            all_env_vars.update(analysis.env_variables)
        
        # 识别最常用的配置系统
        most_used_system = max(system_usage_count.items(), key=lambda x: x[1])
        
        # 将元组键转换为字符串键以便JSON序列化
        system_combinations_str = {
            " + ".join(combo) if combo else "无配置系统": count
            for combo, count in system_combinations.items()
        }
        
        return {
            "总体统计": {
                "服务总数": total_services,
                "配置文件总数": total_config_files,
                "配置使用总数": total_usages,
                "环境变量总数": len(all_env_vars)
            },
            "配置系统使用统计": system_usage_count,
            "最常用配置系统": {
                "系统名称": most_used_system[0],
                "使用服务数": most_used_system[1]
            },
            "配置系统组合使用": system_combinations_str,
            "所有环境变量": sorted(list(all_env_vars))
        }
    
    def generate_detailed_report(self, analyses: Dict[str, ServiceConfigAnalysis]) -> str:
        """生成详细的配置审计报告"""
        report_lines = [
            "# RedFire 后端配置系统使用情况审计报告",
            f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
            "",
            "## 执行概要",
            f"- 扫描服务数量: {len(analyses)}",
            f"- 发现配置文件: {sum(len(a.config_files) for a in analyses.values())} 个",
            f"- 发现配置使用: {sum(len(a.config_usages) for a in analyses.values())} 处",
            ""
        ]
        
        # 生成总结
        summary = self.generate_summary_report(analyses)
        
        report_lines.extend([
            "## 配置系统使用统计",
            ""
        ])
        
        for system, count in summary["配置系统使用统计"].items():
            report_lines.append(f"- **{system}**: {count} 个服务使用")
        
        report_lines.extend([
            "",
            f"**最常用系统**: {summary['最常用配置系统']['系统名称']} "
            f"({summary['最常用配置系统']['使用服务数']} 个服务)",
            "",
            "## 配置系统组合使用情况",
            ""
        ])
        
        for combo, count in summary["配置系统组合使用"].items():
            systems_str = " + ".join(combo) if combo else "无配置系统"
            report_lines.append(f"- **{systems_str}**: {count} 个服务")
        
        # 详细服务分析
        report_lines.extend([
            "",
            "## 各服务详细配置分析",
            ""
        ])
        
        for service_name, analysis in analyses.items():
            report_lines.extend([
                f"### {service_name}",
                "",
                f"**配置文件**: {len(analysis.config_files)} 个"
            ])
            
            for config_file in analysis.config_files[:3]:  # 只显示前3个
                report_lines.append(f"  - {config_file}")
            
            if len(analysis.config_files) > 3:
                report_lines.append(f"  - ... 还有 {len(analysis.config_files) - 3} 个")
            
            report_lines.extend([
                "",
                f"**使用的配置系统**: {', '.join(analysis.config_systems_used) if analysis.config_systems_used else '无'}",
                "",
                f"**配置使用次数**: {len(analysis.config_usages)} 次",
                ""
            ])
            
            if analysis.config_dependencies:
                report_lines.append("**各系统使用频次**:")
                for system, count in analysis.config_dependencies.items():
                    report_lines.append(f"  - {system}: {count} 次")
                report_lines.append("")
            
            if analysis.env_variables:
                env_vars_preview = list(analysis.env_variables)[:5]
                report_lines.append(f"**环境变量**: {len(analysis.env_variables)} 个")
                for var in env_vars_preview:
                    report_lines.append(f"  - {var}")
                if len(analysis.env_variables) > 5:
                    report_lines.append(f"  - ... 还有 {len(analysis.env_variables) - 5} 个")
                report_lines.append("")
            
            report_lines.append("---")
            report_lines.append("")
        
        return "\n".join(report_lines)
    
    def save_reports(self, analyses: Dict[str, ServiceConfigAnalysis]):
        """保存审计报告"""
        # 创建报告目录
        reports_dir = self.backend_path / "reports"
        reports_dir.mkdir(exist_ok=True)
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 保存详细报告
        detailed_report = self.generate_detailed_report(analyses)
        with open(reports_dir / f"config_audit_detailed_{timestamp}.md", 'w', encoding='utf-8') as f:
            f.write(detailed_report)
        
        # 保存JSON数据
        json_data = {
            "timestamp": timestamp,
            "summary": self.generate_summary_report(analyses),
            "services": {
                name: {
                    "service_name": analysis.service_name,
                    "config_files": analysis.config_files,
                    "config_systems_used": list(analysis.config_systems_used),
                    "env_variables": list(analysis.env_variables),
                    "config_dependencies": analysis.config_dependencies,
                    "config_usages": [asdict(usage) for usage in analysis.config_usages]
                }
                for name, analysis in analyses.items()
            }
        }
        
        with open(reports_dir / f"config_audit_data_{timestamp}.json", 'w', encoding='utf-8') as f:
            json.dump(json_data, f, ensure_ascii=False, indent=2)
        
        print(f"审计报告已保存:")
        print(f"  - 详细报告: reports/config_audit_detailed_{timestamp}.md")
        print(f"  - 数据文件: reports/config_audit_data_{timestamp}.json")


def main():
    """主函数"""
    # 获取脚本所在目录，然后找到backend目录
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # 脚本在 tools/ 目录下，backend目录在上一级
    project_root = os.path.dirname(script_dir)
    backend_path = os.path.join(project_root, "backend")
    
    print(f"Script location: {__file__}")
    print(f"Project root: {project_root}")
    print(f"Backend path: {backend_path}")
    
    auditor = ConfigAuditor(backend_path)
    print(f"Services path: {auditor.services_path}")
    
    print("开始配置系统审计...")
    analyses = auditor.analyze_all_services()
    
    if not analyses:
        print("未找到任何服务进行分析")
        return
    
    print("\n生成审计报告...")
    auditor.save_reports(analyses)
    
    # 输出简要总结
    summary = auditor.generate_summary_report(analyses)
    print("\n=== 配置系统使用情况总结 ===")
    for system, count in summary["配置系统使用统计"].items():
        print(f"{system}: {count} 个服务使用")
    
    print(f"\n最常用系统: {summary['最常用配置系统']['系统名称']}")
    print("\n审计完成！")


if __name__ == "__main__":
    main()